package com.inspur.edp.bef.bizentity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Predicate;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.bef.bizentity.gspbusinessentity.entity.BeConfigCollectionInfo;
import com.inspur.edp.bef.bizentity.gspbusinessentity.entity.GspBeExtendInfo;
import com.inspur.edp.bef.bizentity.json.model.BizEntityDeserializer;
import com.inspur.edp.bef.bizentity.json.model.BizEntitySerializer;
import com.inspur.edp.bef.bizentity.operation.BizMgrAction;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.bizentity.operation.Determination;
import com.inspur.edp.bef.bizentity.operation.collection.BizMgrActionCollection;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.*;
import com.inspur.edp.caf.cef.schema.structure.CommonStructure;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.entity.config.CefConfig;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.util.CommonModelExtension;
import com.inspur.edp.bef.bizentity.beenum.BECategory;
import com.inspur.edp.bef.bizentity.beenum.BETriggerTimePointType;
import com.inspur.edp.bef.bizentity.beenum.GspDataLockType;
// import Inspur.Gsp.Das.CommonModel.*;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
// import Inspur.Gsp.Lcm.Metadata.Api.*;

/**
 * 业务实体元数据实体类
 * <p>
 * 新建业务实体，如下所示：
 * <blockquote><pre>
 *		GspBusinessEntity be = new GspBusinessEntity();
 *		be.setID(Guid.newGuid().toString());
 *		be.setCode("beCode");
 *		be.setName("业务实体");
 * </pre></blockquote>
 * <p>
 * 新建业务实体对象节点:{@link GspBizEntityObject}
 * <p>
 * 新建字段实体：{@link GspBizEntityElement}
 *
 */
// C# TO JAVA CONVERTER TODO TASK: Java annotations will not correspond to .NET
// attributes:
// [, System.Diagnostics.debuggerDisplay("Code={Code}, ID={ID}")]
@JsonSerialize(using = BizEntitySerializer.class)
@JsonDeserialize(using = BizEntityDeserializer.class)
public class GspBusinessEntity extends GspCommonModel implements IMetadataContent {
	// region 属性

	/**
	 * 获取业务实体扩展信息
	 * @param type
	 * @return <tt>GspBeExtendInfo</tt>
	 */
    public final GspBeExtendInfo getGspBeExtendInfo(ProcessMode type){
    	GspBeExtendInfo beExtendInfo = new GspBeExtendInfo();
    	beExtendInfo.setId(this.getID());
    	beExtendInfo.setConfigId(this.getGeneratedConfigID());
    	beExtendInfo.setLastChangedOn(new Date());
		BeConfigCollectionInfo beConfigCollectionInfo = getBefConfigCollectionInfo(this);
		beConfigCollectionInfo.setProjectType(type);
    	beExtendInfo.setBeConfigCollectionInfo(beConfigCollectionInfo);
    	return beExtendInfo;
	}

	private BeConfigCollectionInfo getBefConfigCollectionInfo(GspBusinessEntity be) {
		CefConfig cefConfig = new CefConfig();
		cefConfig.setID(be.getGeneratedConfigID());
		cefConfig.setBEID(be.getID());
		String nameSpace = be.getCoreAssemblyInfo().getDefaultNamespace();
		cefConfig.setDefaultNamespace(nameSpace.toLowerCase());
		BeConfigCollectionInfo beConfigCollectionInfo = new BeConfigCollectionInfo();
		beConfigCollectionInfo.setConfig(cefConfig);
		return beConfigCollectionInfo;
	}
	/**
	 * 生成构件程序集名
	 */
	private String privateComponentAssemblyName;

	public final String getComponentAssemblyName() {
		return privateComponentAssemblyName;
	}

	public final void setComponentAssemblyName(String value) {
		privateComponentAssemblyName = value;
	}

	/**
	 * BE 实体类型
	 */
	private BECategory privateCategory = BECategory.forValue(0);

	public BECategory getCategory() {
		return privateCategory;
	}

	public void setCategory(BECategory value) {
		privateCategory = value;
	}

	/**
	 * BE根节点
	 */
	public final GspBizEntityObject getMainObject() {
		return (GspBizEntityObject) super.getMainObject();
	}

	public final void setMainObject(GspBizEntityObject value) {

		super.setCmMainObject(value);
	}

	/**
	 * 实体数据加锁类型 此属性影响到实体使用乐观锁或者悲观锁控制数据并发 默认为悲观锁，保证更好的数据一致性，同时可以提升用户体验。必须显式加锁才能编辑数据
	 */
	private GspDataLockType privateDataLockType = GspDataLockType.forValue(0);

	public final GspDataLockType getDataLockType() {
		return privateDataLockType;
	}

	public final void setDataLockType(GspDataLockType value) {
		privateDataLockType = value;
	}

	/**
	 * 扩展类型，固定返回业务实体类型，用于兼容
	 */
	@Override
	public String getExtendType() {
		return "GspBusinessEntity";
	}

	private String dependentEntityId;
	private String dependentEntityName;
	private String dependentEntityPackageName;

	boolean isUsingTimeStamp;
	boolean enableCaching = false;
	boolean enableTreeDtm = true;
	private String cacheConfiguration = "";
	private boolean enableApproval = false;
	private boolean tccSupported = false;
	private boolean autoTccLock = true;
	private boolean autoComplete = true;
	private boolean autoCancel = true;

	/**
	 * 是否启用TCC
	 */
	public boolean isTccSupported() {
		return tccSupported;
	}

	public void setTccSupported(boolean tccSupported) {
		this.tccSupported = tccSupported;
	}

	/**
	 * 是否自动添加TCC锁
	 */
	public boolean isAutoTccLock() {
		return autoTccLock;
	}

	public void setAutoTccLock(boolean autoTccLock) {
		this.autoTccLock = autoTccLock;
	}

	/**
	 * 是否启用自动完成
	 */
	public boolean isAutoComplete() {
		return autoComplete;
	}

	public void setAutoComplete(boolean autoComplete) {
		this.autoComplete = autoComplete;
	}

	/**
	 * 是否启用启动取消
	 */
	public boolean isAutoCancel() {
		return autoCancel;
	}

	public void setAutoCancel(boolean autoCancel) {
		this.autoCancel = autoCancel;
	}

	/**
	 * 被依赖实体的id
	 */
	public String getDependentEntityId() {
		return dependentEntityId;
	}

	public void setDependentEntityId(String value) {
		dependentEntityId = value;
	}

	/**
	 * 被依赖实体的名称
	 */
	public String getDependentEntityName() {
		return dependentEntityName;
	}

	public void setDependentEntityName(String value) {
		dependentEntityName = value;
	}

	/**
	 * 被依赖的实体包名
	 */
	public String getDependentEntityPackageName() {
		return dependentEntityPackageName;
	}

	public void setDependentEntityPackageName(String value) {
		dependentEntityPackageName = value;
	}

	private BizMgrActionCollection beMgrActions;

	/**
	 * @return <tt>BizMgrActionCollection</tt>返回所有实体上的外部动作集合
	 */
	public final BizMgrActionCollection getBizMgrActions() {
		if (beMgrActions == null) {
			beMgrActions = new BizMgrActionCollection();
		}
		beMgrActions.setOwner(this.getMainObject());
		return beMgrActions;
	}

	public final void setBizMgrActions(BizMgrActionCollection value) {
		beMgrActions = value;
		beMgrActions.setOwner(this.getMainObject());
	}

	// private java.util.ArrayList<AuthorizationInfo> authorizations;

	/**
	 * BE关联的权限对象ID集合
	 *
	 */
	// java.util.ArrayList<AuthorizationInfo> getAuthorizations()

	// public void setAuthorizations(java.util.ArrayList<AuthorizationInfo> value)

	/**
	 * 是否生成时间戳字段（仅主表）
	 */
	public boolean getIsUsingTimeStamp() {
		return isUsingTimeStamp;
	}

	public void setIsUsingTimeStamp(boolean value) {
		isUsingTimeStamp = value;
	}

	/**
	 * 是否启用审批
	 */
	public boolean getEnableApproval() { return  enableApproval; }
	public void setEnableApproval(boolean value) {
		enableApproval = value;
	}

	/**
	 * 缓存配置
	 */
	public String getCacheConfiguration() {
		return cacheConfiguration;
	}

	public void setCacheConfiguration(String value) {
		cacheConfiguration = value;
	}

	/**
	 * 是否启用缓存
	 */
	public boolean getEnableCaching() {
		return enableCaching;
	}

	public void setEnableCaching(boolean value) {
		enableCaching = value;
	}

	/**
	 * 是否启用树内置动作
	 */
	public boolean getEnableTreeDtm() {
		return enableTreeDtm;
	}

	public void setEnableTreeDtm(boolean value) {
		enableTreeDtm = value;
	}

	// endregion

	// region Ctor
	public GspBusinessEntity() {
		getBizMgrActions().add(new QueryMgrAction());
		getBizMgrActions().add(new RetrieveDefaultMgrAction());
		getBizMgrActions().add(new RetrieveMgrAction());
		getBizMgrActions().add(new ModifyMgrAction());
		getBizMgrActions().add(new DeleteMgrAction());
	}
	// C# TO JAVA CONVERTER TODO TASK: There is no preprocessor in Java:
	/// endregion

	// region 方法

	/**
	 * @return <tt>ArrayList<String></tt>获取BE上所有的dbo
	 */
	public final ArrayList<String> getAllDbos(){
		ArrayList<String> list=new ArrayList<>();
		for (GspBizEntityObject object:getAllNodes()){
			list.add(object.getRefObjectName());
		}
		return list;
	}
	/**
	 * 遍历所有BE节点列表
	 * @return <tt>ArrayList<GspBizEntityObject></tt>按照层次遍历的BE结点列表,先根遍历
	 */
	public final java.util.ArrayList<GspBizEntityObject> getAllNodes() {
		ArrayList<IGspCommonObject> list = CommonModelExtension.getLevelOrderedNodes(this);
		ArrayList<GspBizEntityObject> bizObjs = new ArrayList<GspBizEntityObject>();
		for (IGspCommonObject item : list) {
			bizObjs.add((GspBizEntityObject) item);
		}
		return bizObjs;
	}

	/**
	 * 查询符合条件的Node集合
	 *
	 * @param predicate 查询条件
	 * @return <tt>ArrayList<GspBizEntityObject></tt>返回结果按照层次遍历顺序
	 */
	public final ArrayList<GspBizEntityObject> getAllNodes(Predicate<GspBizEntityObject> predicate) {

		ArrayList<GspBizEntityObject> bizObjs = getAllNodes();
		ArrayList<GspBizEntityObject> result = new ArrayList<GspBizEntityObject>();
		for (GspBizEntityObject item : bizObjs) {
			if (predicate.test(item)) {
				result.add(item);
			}
		}
		return result;
	}

	/**
	 * 查询符合条件的第一个节点
	 *
	 * @param predicate
	 * @return <tt>GspBizEntityObject</tt>返回第一个结果，如果没有符合条件的结果则返回null
	 */
	public final GspBizEntityObject getNode(Predicate<GspBizEntityObject> predicate) {
		ArrayList<GspBizEntityObject> result = getAllNodes(predicate);
		if (result.size() > 0) {
			return result.get(0);
		}
		return null;
	}

	/**
	 * 查询指定Code的节点
	 *
	 * @param nodeCode 节点编号
	 * @return <tt>GspBizEntityObject</tt>符合条件的节点对象
	 */
	public final GspBizEntityObject getNode(String nodeCode) {
		return getNode(pre -> pre.getCode().equals(nodeCode));
	}

	public final IGspCommonModel copyToCommonModel() {
		// TODO 后续换成Copy方法
		return this;
	}

	/**
	 * 获取某一执行时机所有的联动计算，并按子表动作在先主表动作在后进行排序
	 *
	 * @param timePoint 执行时机
	 * @return <tt>ArrayList<Determination></tt> 如果找不到返回空集合
	 */
	public final java.util.ArrayList<Determination> getAllDtmWithTriggerTime(BETriggerTimePointType timePoint) {
		java.util.ArrayList<Determination> dtms = new java.util.ArrayList<Determination>();
		java.util.Stack<GspBizEntityObject> bizObjecs = new java.util.Stack<GspBizEntityObject>();
		getBizObjectFromChildToParent(new java.util.ArrayList<GspBizEntityObject>(
				java.util.Arrays.asList(new GspBizEntityObject[]{getMainObject()})), bizObjecs);
		while (bizObjecs.size() > 0) {
			ArrayList<Determination> list = bizObjecs.pop().getDeterminations()
					.getFiltedDtms(dtm -> dtm.getTriggerTimePointType().contains(timePoint));
			dtms.addAll(list);
		}
		return dtms;
	}

	/**
	 * 按先子后主的顺序，获取所有的节点
	 *
	 * @param childObjects 子表对象
	 * @param bizObjects
	 */
	private void getBizObjectFromChildToParent(java.util.ArrayList<GspBizEntityObject> childObjects,
			java.util.Stack<GspBizEntityObject> bizObjects) {
		if (childObjects.size() > 0) {
			java.util.ArrayList<GspBizEntityObject> childs = new java.util.ArrayList<GspBizEntityObject>();
			for (IGspCommonObject obj : childObjects) {
				GspBizEntityObject item = (GspBizEntityObject) obj;
				bizObjects.push(item);

				for (IGspCommonObject childObj : item.getContainChildObjects()) {
					childs.add((GspBizEntityObject) childObj);
				}
			}
			getBizObjectFromChildToParent(childs, bizObjects);
		}
	}

	/**
	 * 合并自模板实体
	 *
	 * @param dependentEntity 模板实体
	 */
	public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity) {
		mergeWithDependentEntity(dependentEntity, false);
	}

	public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity, boolean isInit) {
		if (dependentEntity.getCategory() != BECategory.DependentBusinessEntity) {
			throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0086, "DependentBusinessEntity");
		}
		// 初始化dbe带出主对象
		getMainObject().setIsRef(true);

		getMainObject().mergeWithDependentObject(dependentEntity.getMainObject(), isInit);
		mergeMgrActions(dependentEntity);
	}

	private void mergeMgrActions(GspBusinessEntity dependentEntity) {
		getBizMgrActions().mergeDbeOperations(dependentEntity.getBizMgrActions());
	}

	/**
	 * 克隆
	 *
	 * @return <tt>GspBusinessEntity</tt> 克隆返回一个全新的业务实体
	 */
	// C# TO JAVA CONVERTER WARNING: There is no Java equivalent to C#'s shadowing
	// via the 'new' keyword:
	// ORIGINAL LINE: public new object clone()
	public GspBusinessEntity clone() {
		GspBusinessEntity be = (GspBusinessEntity) super.clone();
		if (be == null) {
			return null;
		}
		if (getBizMgrActions() != null) {
			Object tempVar = getBizMgrActions().clone();
			be.setBizMgrActions((BizMgrActionCollection) ((tempVar instanceof BizMgrActionCollection) ? tempVar : null));
		}
		return be;
	}

	// endregion

	// region IEntityObject.GetRefStructures
	@Override
	protected List<CommonStructure> getCommonModelRefStructures() {
		List<IGspCommonField> fields = new ArrayList<>();
		for (IGspCommonField field : getAllElementList(false)) {
			fields.add(field);
		}
		//TODO 临时注释
		return null;
//		return BeCommonStructureUtil.getInstance().getElementsRefStructures(fields);
	}

	public BizMgrActionCollection getCustomMgrActions() {
		BizMgrActionCollection mgrActions=new BizMgrActionCollection();
		for(BizOperation operation:this.getBizMgrActions()){
			if(operation instanceof IInternalMgrAction)
				continue;
			mgrActions.add((BizMgrAction) operation);
		}
		return mgrActions;
	}
	public GspCommonModel getNewInstance() {
		ObjectMapper mapper = getMapper();
		try {
			String json = mapper.writeValueAsString(this);
			GspBusinessEntity businessEntity=mapper.readValue(json,GspBusinessEntity.class);
			return businessEntity;
		}catch (JsonProcessingException e){
			throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0013, e, "GspBusinessEntity");
		}
	}
	private ObjectMapper getMapper(){
		ObjectMapper mapper=new ObjectMapper();
		SimpleModule module=new SimpleModule();
		module.addSerializer(IGspCommonModel.class,new BizEntitySerializer());
		module.addDeserializer(IGspCommonModel.class,new BizEntityDeserializer());
		mapper.registerModule(module);
		return mapper;
	}
}
